www.gusucode.com > VC++写的C编译器源代码附设计文档-源码程序 > VC++写的C编译器源代码附设计文档-源码程序/code/C- Compiler/MenuWndHook.cpp

    //Download by http://www.NewXing.com
/*########################################################################
	Filename: 	MenuWndHook.cpp
	----------------------------------------------------
	Remarks:	...
	----------------------------------------------------
	Author:		成真
	Email:		anyou@sina.com
				anyou@msn.com
	Created:	7/4/2003 17:38
  ########################################################################*/

#include "stdafx.h"
#include "resource.h"
#include "MenuWndHook.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#ifndef SPI_GETDROPSHADOW
#define SPI_GETDROPSHADOW   0x1024
#endif
const TCHAR CoolMenu_oldProc[] = _T("CoolMenu_oldProc");

/*========================================================================
	说明:	检测系统是否开启了菜单阴影(主要针对于Windows XP, Windows 2003
		及他更高的版本).	
==========================================================================*/
BOOL WINAPI IsShadowEnabled()
{
	BOOL bEnabled = FALSE;
	if (SystemParametersInfo(SPI_GETDROPSHADOW, 0, &bEnabled, 0))
	{
		return bEnabled;
	}
	return FALSE;
}

/*========================================================================
	说明:		截取屏幕上指定区域内的图像.
==========================================================================*/
HBITMAP WINAPI GetScreenBitmap(LPCRECT pRect)
{
    HDC     hDC;
    HDC     hMemDC;
    HBITMAP hNewBitmap = NULL;
	
    if ((hDC = ::GetDC(NULL)) != NULL )
    {
        if ((hMemDC = ::CreateCompatibleDC(hDC)) != NULL)
        {
            if ((hNewBitmap = ::CreateCompatibleBitmap(hDC, pRect->right - pRect->left, pRect->bottom - pRect->top)) != NULL)
            {
                HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hNewBitmap);
                ::BitBlt(hMemDC, 0, 0, pRect->right - pRect->left, pRect->bottom - pRect->top,
					hDC, pRect->left, pRect->top, SRCCOPY);
                ::SelectObject(hMemDC, (HGDIOBJ)hOldBitmap);
            }
            ::DeleteDC(hMemDC);
        }
        ::ReleaseDC(NULL, hDC);
    }
    return hNewBitmap;
}

/*========================================================================
	说明:	在指定的矩形区域内绘制阴影.	
==========================================================================*/
void DrawShadow(CDC *pDC, CRect rect)
{
	COLORREF oldcolor = RGB(255, 255, 255);
	BYTE newValR, newValG, newValB;
	BYTE AlphaArray[] = {140, 170, 212, 240};
	BYTE AlphaArray2[] = {170, 205, 220, 240, 240, 250, 255};
	
	// 底部的阴影 -----------------------------------------
	int i, j;
	for (j = 0; j < 4; j++)
	{
		for (i = 6; i <= rect.right - 5; i++)
		{
			oldcolor = pDC->GetPixel(i, rect.bottom - (4 - j));
			newValR = GetRValue(oldcolor) * AlphaArray[j] / 255;  
			newValG = GetGValue(oldcolor) * AlphaArray[j] / 255;  
			newValB = GetBValue(oldcolor) * AlphaArray[j] / 255;  
			pDC->SetPixel(i, rect.bottom - (4 - j), RGB(newValR, newValG, newValB));
		}
	}
	
	// 右边的阴影 -----------------------------------------
	for (i = 0; i < 4; i++)
	{
		for (j = 6; j <= rect.bottom - 5; j++)
		{
			oldcolor = pDC->GetPixel(rect.right - (4 - i), j);
			newValR = GetRValue(oldcolor) * AlphaArray[i] / 255;  
			newValG = GetGValue(oldcolor) * AlphaArray[i] / 255;  
			newValB = GetBValue(oldcolor) * AlphaArray[i] / 255;  
			pDC->SetPixel(rect.right - (4 - i), j, RGB(newValR, newValG, newValB));
		}
	}
	
	// 其他部位的阴影 --------------------------------------
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 4; j++)
		{
			if ((i + j) > 6) break;
			BYTE alpha = AlphaArray2[i + j];
			oldcolor = pDC->GetPixel(rect.right - 4 + i, rect.bottom - 4 + j);
			newValR = GetRValue(oldcolor) * alpha / 255;  
			newValG = GetGValue(oldcolor) * alpha / 255;  
			newValB = GetBValue(oldcolor) * alpha / 255;  
			pDC->SetPixel(rect.right - 4 + i, rect.bottom - 4 + j, RGB(newValR, newValG, newValB));
			
			oldcolor = pDC->GetPixel(rect.right - 4 + i, rect.top + 5 - j);
			newValR = GetRValue(oldcolor) * alpha / 255;  
			newValG = GetGValue(oldcolor) * alpha / 255;  
			newValB = GetBValue(oldcolor) * alpha / 255;  
			pDC->SetPixel(rect.right - 4 + i, rect.top + 5 - j, RGB(newValR, newValG, newValB));
			
			oldcolor = pDC->GetPixel(rect.left - i + 5, rect.bottom - 4 + j);
			newValR = GetRValue(oldcolor) * alpha / 255;  
			newValG = GetGValue(oldcolor) * alpha / 255;  
			newValB = GetBValue(oldcolor) * alpha / 255;  
			pDC->SetPixel(rect.left - i + 5, rect.bottom - 4 + j, RGB(newValR, newValG, newValB));
		}
	}
}

/*########################################################################
			  ------------------------------------------------
								class CMenuWndHook
			  ------------------------------------------------
  ########################################################################*/
CMap <HWND, HWND, CMenuWndHook*, CMenuWndHook*> CMenuWndHook::m_WndMenuMap;
HHOOK CMenuWndHook::m_hMenuHook = NULL;
COLORREF CMenuWndHook::m_crFrame[4] = 
	{::GetSysColor(COLOR_3DSHADOW), 
	 ::GetSysColor(COLOR_3DSHADOW), 
	 ::GetSysColor(COLOR_MENU), 
	 ::GetSysColor(COLOR_MENU)};

CMenuWndHook::CMenuWndHook (HWND hWnd)
: m_hWnd(hWnd)
{

}

CMenuWndHook::~CMenuWndHook ()
{
    WNDPROC oldWndProc = (WNDPROC)::GetProp(m_hWnd, CoolMenu_oldProc);
    if (oldWndProc != NULL)
    {
        ::SetWindowLong(m_hWnd, GWL_WNDPROC, (DWORD)(ULONG)oldWndProc);
        ::RemoveProp(m_hWnd, CoolMenu_oldProc);
    }
    m_WndMenuMap.RemoveKey(m_hWnd);
	if (m_bmpBack.m_hObject != NULL )
    {
         m_bmpBack.DeleteObject();
    }
}

void CMenuWndHook::InstallHook()
{
    if (m_hMenuHook == NULL )
    {
        m_hMenuHook = ::SetWindowsHookEx(WH_CALLWNDPROC, WindowHook, 
						AfxGetApp()->m_hInstance, ::GetCurrentThreadId());
    }
}

void CMenuWndHook::UnInstallHook()
{
    POSITION pos = m_WndMenuMap.GetStartPosition();
    while (pos != NULL)
    {
        HWND hwnd;
        CMenuWndHook* pMenuWndHook;
        m_WndMenuMap.GetNextAssoc(pos, hwnd, pMenuWndHook);
        delete pMenuWndHook;
		pMenuWndHook = NULL;
    }
    m_WndMenuMap.RemoveAll();
	
    if (m_hMenuHook != NULL)
    {
        ::UnhookWindowsHookEx(m_hMenuHook);
    }
}

CMenuWndHook* CMenuWndHook::GetWndHook(HWND hwnd)
{
    CMenuWndHook* pWnd = NULL;
    if (m_WndMenuMap.Lookup(hwnd, pWnd))
    {
        return pWnd;
    }
    return NULL;
}

CMenuWndHook* CMenuWndHook::AddWndHook(HWND hwnd)
{
	CMenuWndHook* pWnd = NULL;
	if (m_WndMenuMap.Lookup(hwnd, pWnd))
	{
	   return pWnd;
	}

	pWnd = new CMenuWndHook(hwnd);
	if (pWnd != NULL)
	{
		m_WndMenuMap.SetAt(hwnd, pWnd);
	}
	return pWnd;
}

/*########################################################################
			  ------------------------------------------------
								  消息过程
			  ------------------------------------------------
  ########################################################################*/
LRESULT CALLBACK CMenuWndHook::WindowHook(int code, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
	
    while (code == HC_ACTION)
    {
        HWND hWnd = pStruct->hwnd;
		
        if (pStruct->message != WM_CREATE && pStruct->message != 0x01E2)
        {
            break;
        }

        // 是否为菜单类 ----------------------------------------
        TCHAR strClassName[10];
        int Count = ::GetClassName (hWnd, strClassName, sizeof(strClassName) / sizeof(strClassName[0]));
        if (Count != 6 || _tcscmp(strClassName, _T("#32768")) != 0 )
        {
            break;
        }
		
		// 是否已经被子类化 ------------------------------------
        if (::GetProp(pStruct->hwnd, CoolMenu_oldProc) != NULL )
        {
            break;
        }
        VERIFY(AddWndHook(pStruct->hwnd) != NULL);

        // 取得原来的窗口过程 ----------------------------------
        WNDPROC oldWndProc = (WNDPROC)(long)::GetWindowLong(pStruct->hwnd, GWL_WNDPROC);
        if (oldWndProc == NULL)
        {
            break;
        }
		
        ASSERT(oldWndProc != CoolMenuProc);
        // 保存到窗口的属性中 ----------------------------------
        if (!SetProp(pStruct->hwnd, CoolMenu_oldProc, oldWndProc) )
        {
            break;
        }

        // 子类化 ----------------------------------------------
        if (!SetWindowLong(pStruct->hwnd, GWL_WNDPROC,(DWORD)(ULONG)CoolMenuProc) )
        {
            ::RemoveProp(pStruct->hwnd, CoolMenu_oldProc);
            break;
        }
        break;
    }
    return CallNextHookEx (m_hMenuHook, code, wParam, lParam);
}

LRESULT CALLBACK CMenuWndHook::CoolMenuProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	WNDPROC oldWndProc = (WNDPROC)::GetProp(hWnd, CoolMenu_oldProc);
    CMenuWndHook* pWnd = NULL;
	
    switch (uMsg)
    {
		case WM_NCCALCSIZE:
			{
				LRESULT lResult = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam);
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnNcCalcsize((NCCALCSIZE_PARAMS*)lParam);
				}
				return lResult;
			}
			break;
		case WM_WINDOWPOSCHANGING:
			{
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnWindowPosChanging((LPWINDOWPOS)lParam);
				}
			}
			break;
		case WM_PRINT:
			{
				LRESULT lResult = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam);
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnPrint(CDC::FromHandle((HDC)wParam));
				}
				return lResult;
			}
			break;
		case WM_NCPAINT:
			{
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnNcPaint();
					return 0;
				}
			}
			break;
		case WM_SHOWWINDOW:
			{
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnShowWindow(wParam != NULL);
				}
			}
			break;
		case WM_NCDESTROY:
			{
				if ((pWnd = GetWndHook(hWnd)) != NULL)
				{
					pWnd->OnNcDestroy();
				}
			}
			break;
    }
    return CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam);
}

/*########################################################################
			  ------------------------------------------------
								消息处理函数	
			  ------------------------------------------------
  ########################################################################*/
void CMenuWndHook::OnWindowPosChanging(WINDOWPOS *pWindowPos)
{
	if (!IsShadowEnabled())
	{
		pWindowPos->cx += 4;
		pWindowPos->cy += 4;
	}

	if (!IsWindowVisible(m_hWnd) && !IsShadowEnabled())
    {
       if (m_bmpBack.m_hObject != NULL )
        {
            m_bmpBack.DeleteObject();
        }
        m_bmpBack.Attach(GetScreenBitmap(CRect(pWindowPos->x, pWindowPos->y, pWindowPos->cx, pWindowPos->cy)));
    }
}

void CMenuWndHook::OnNcCalcsize(NCCALCSIZE_PARAMS* lpncsp)
{
	if (!IsShadowEnabled())
	{
		 lpncsp->rgrc[0].right -= 4;
		 lpncsp->rgrc[0].bottom -= 4;
	}
}

void CMenuWndHook::OnNcPaint()
{
    CWindowDC dc(CWnd::FromHandle(m_hWnd));
	OnPrint(&dc);
}

void CMenuWndHook::OnPrint(CDC *pDC)
{
	CRect rc;
	GetWindowRect(m_hWnd, &rc);
    rc.OffsetRect(-rc.TopLeft());
	
	if (!IsShadowEnabled())
	{
		CDC cMemDC;
		cMemDC.CreateCompatibleDC (pDC);
		HGDIOBJ hOldBitmap = ::SelectObject (cMemDC.m_hDC, m_bmpBack);
		pDC->BitBlt (0, rc.bottom - 4, rc.Width() - 4, 4, &cMemDC, 0, rc.bottom - 4, SRCCOPY);
		pDC->BitBlt (rc.right - 4, 0, 4, rc.Height(), &cMemDC, rc.right - 4, 0, SRCCOPY);
		
		DrawShadow(pDC, rc);
		rc.right -= 4;
		rc.bottom -= 4;
	}

	pDC->Draw3dRect(rc, m_crFrame[0], m_crFrame[1]);
	rc.DeflateRect (1, 1);
	pDC->Draw3dRect(rc, m_crFrame[2], m_crFrame[3]);
	rc.DeflateRect (1, 1);
	pDC->Draw3dRect(rc, m_crFrame[2], m_crFrame[3]);
}

void CMenuWndHook::OnNcDestroy()
{
	delete this;
}

void CMenuWndHook::OnShowWindow(BOOL bShow)
{
    if (!bShow)
    {
        delete this;
    }
}